import asyncio
import fractions
import json
import os
import sys
import traceback
import uuid
import numpy as np
from PIL import Image, ImageDraw
from PIL.ImageQt import ImageQt
from PyQt6.QtGui import QIcon, QPixmap
from PyQt6.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QWidget,
                             QPushButton, QFileDialog, QLineEdit, QLabel, QTextEdit, QSpinBox, QHBoxLayout, QComboBox,
                             QFormLayout, QCheckBox)
from PyQt6.QtCore import QThread, pyqtSignal, QDateTime, QByteArray, QBuffer, QIODevice, Qt
from setuptools import glob

icon_data = "AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAADg4OD/5+fn/+jo6P/n5+f/4+Pj/3V1df8DAwP/BAQE/wQEBP8EBAT/BAQE/wQEBP8FBQX/BQUF/wUFBf8EBAT/BQUF/wcHB/8GBgb/BQUF/wQEBP8EBAT/AgIC/xwcHP9ubm7/hISE/8jIyP/T09P/0dHR/9HR0f/R0dH/z8/P/+Dg4P/Gxsb/ysrK/97e3v/Y2Nj/VFRU/wEBAf8EBAT/BAQE/wQEBP8EBAT/BQUF/wUFBf8GBgb/BQUF/wUFBf8GBgb/BgYG/wYGBv8EBAT/BAQE/wQEBP8DAwP/DQ0N/21tbf+CgoL/np6e/8jIyP/Ly8v/0tLS/9TU1P/R0dH/0dHR/5ubm/+lpaX/3Nzc/83Nzf8/Pz//AQEB/wQEBP8EBAT/BAQE/wUFBf8GBgb/BgYG/wYGBv8FBQX/BgYG/wYGBv8GBgb/BQUF/wQEBP8EBAT/BAQE/wQEBP8ICAj/W1tb/4SEhP+Li4v/tbW1/8rKyv/R0dH/zs7O/8PDw//W1tb/zc3N/7a2tv+6urr/np6e/yAgIP8CAgL/BAQE/wUFBf8FBQX/BQUF/wYGBv8GBgb/BgYG/wYGBv8FBQX/BgYG/wYGBv8FBQX/BAQE/wQEBP8EBAT/BAQE/wkJCf9ra2v/h4eH/5SUlP+srKz/jo6O/4uLi/9+fn7/bm5u/8bGxv/FxcX/tra2/62trf99fX3/DAwM/wMDA/8EBAT/BQUF/wYGBv8GBgb/BgYG/wYGBv8GBgb/BgYG/wYGBv8FBQX/BgYG/wUFBf8EBAT/BAQE/wQEBP8EBAT/CQkJ/2NjY/+Pj4//lpaW/6SkpP9fX1//WFhY/1dXV/9UVFT/tra2/6+vr/+vr6//s7Oz/3p6ev8HBwf/BAQE/wQEBP8FBQX/BgYG/wYGBv8GBgb/BgYG/wYGBv8GBgb/BgYG/wYGBv8GBgb/BQUF/wQEBP8EBAT/BAQE/wMDA/8DAwP/Dw8P/zU1Nf91dXX/qamp/2ZmZv9SUlL/UVFR/05OTv+urq7/sLCw/5ycnP+Tk5P/X19f/wsLC/8EBAT/BQUF/wUFBf8GBgb/BgYG/wYGBv8GBgb/BgYG/wYGBv8GBgb/BQUF/wUFBf8GBgb/BQUF/wQEBP8EBAT/BAQE/wQEBP8EBAT/AgIC/xgYGP+MjIz/W1tb/01NTf9MTEz/TExM/3Jycv9UVFT/JiYm/xsbG/8LCwv/BgYG/wUFBf8GBgb/BgYG/wYGBv8GBgb/BwcH/wcHB/8HBwf/BwcH/wYGBv8HBwf/CAgI/wwMDP8FBQX/BAQE/wQEBP8EBAT/BAQE/wQEBP8EBAT/ExMT/2pqav9ISEj/SkpK/0dHR/9JSUn/FRUV/xEREf8JCQn/BQUF/wYGBv8GBgb/BQUF/wYGBv8GBgb/BgYG/wYGBv8HBwf/BwcH/wcHB/8HBwf/BwcH/wcHB/8KCgr/DAwM/wUFBf8EBAT/BQUF/wUFBf8EBAT/BAQE/wQEBP8LCwv/PDw8/0dHR/9JSUn/RkZG/0JCQv8TExP/GBgY/xcXF/8RERH/DAwM/wYGBv8GBgb/BwcH/wcHB/8HBwf/BwcH/wcHB/8ICAj/CAgI/wcHB/8ICAj/CAgI/wsLC/8KCgr/BgYG/wYGBv8EBAT/BAQE/wQEBP8EBAT/BAQE/w0NDf86Ojr/R0dH/0pKSv9GRkb/SEhI/yAgIP8gICD/KSkp/ycnJ/8bGxv/CAgI/wYGBv8HBwf/BwcH/wcHB/8ICAj/CAgI/wgICP8ICAj/CAgI/wcHB/8HBwf/CQkJ/wcHB/8HBwf/BwcH/wYGBv8EBAT/BAQE/wQEBP8DAwP/FhYW/0FBQf9FRUX/Q0ND/0JCQv9NTU3/LCws/ykpKf8vLy//LCws/yEhIf8JCQn/BgYG/wcHB/8HBwf/BwcH/wkJCf8ICAj/CAgI/wgICP8ICAj/CAgI/wgICP8ICAj/BwcH/wgICP8ICAj/BwcH/wYGBv8EBAT/BAQE/wQEBP8mJib/R0dH/0pKSv9ISEj/Q0ND/0VFRf8zMzP/Ly8v/zQ0NP84ODj/LCws/wsLC/8GBgb/BwcH/wcHB/8ICAj/CQkJ/wgICP8ICAj/CAgI/wgICP8JCQn/CQkJ/wgICP8ICAj/CAgI/wgICP8ICAj/BgYG/wUFBf8EBAT/CQkJ/z09Pf9OTk7/SEhI/0hISP9FRUX/QkJC/y4uLv8uLi7/MzMz/zY2Nv8vLy//DAwM/wcHB/8HBwf/BwcH/wkJCf8ICAj/CAgI/wkJCf8ICAj/CQkJ/woKCv8JCQn/CAgI/wgI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"
# 获取脚本所在的目录
script_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
result_dir = ''  # 构造输出文件夹目录的绝对路径
first_file_path = ''  # 要查询的文件路径


class Worker:
    def __init__(self, file_path_1, file_path_2, result_dir, config_path, log_signal=None, mode_open=True):
        self.log_signal = log_signal
        self.ditu_file_path = file_path_1
        self.sucai_file_path = file_path_2
        self.result_dir = result_dir
        self.config = self.load_config(f'{config_path}')  # 加载配置文件
        self.mode_open = mode_open

    def load_config(self, config_file):
        with open(config_file, 'r', encoding='utf-8') as file:
            return json.load(file)

    def get_fixed_box(self, ditu, ratio):
        for mapping in self.config['mappings']:
            if mapping['type'] in ditu and mapping['ratio'] == ratio:
                return tuple(mapping['box'])
        return None  # 如果没有匹配的，返回 None 或设置一个默认值

    def merge_images(self, img1_path, img2_path, output_path, box, mode=None, is_mode_open=True):
        """
        合并两张图片，并应用指定的混合模式
        :param img1_path: 底图图片路径
        :param img2_path: 素材图片路径
        :param output_path: 输出文件路径
        :param box: 素材贴图盒子
        :param mode: 混合模式 ('lighten' 或 'linear_burn')，如果为 None 则根据 img1 的中心像素确定
        :return:
        """
        img1 = Image.open(img1_path).convert("RGBA")
        img2 = Image.open(img2_path).convert("RGBA")
        img1_width, img1_height = img1.size
        img2_width, img2_height = img2.size

        # 新定义的 box 值
        top_dist, bottom_dist, left_dist, right_dist = box

        # 计算红框的坐标
        box_left = left_dist
        box_upper = top_dist
        box_right = img1_width - right_dist
        box_lower = img1_height - bottom_dist

        # 计算红框的宽度和高度
        box_width = box_right - box_left
        box_height = box_lower - box_upper

        # 缩放 img2 以适应红框的宽度
        width_ratio = box_width / img2_width
        scale_ratio = width_ratio

        new_width = int(img2_width * scale_ratio)
        new_height = int(img2_height * scale_ratio)
        img2_resized = img2.resize((new_width, new_height), Image.Resampling.LANCZOS)

        # 如果缩放后的图像高度超出红框范围，根据高度缩放
        if img2_resized.height > box_height:
            height_ratio = box_height / img2_resized.height
            scale_ratio = height_ratio
            new_width = int(img2_resized.width * scale_ratio)
            new_height = int(img2_resized.height * scale_ratio)
            img2_resized = img2_resized.resize((new_width, new_height), Image.Resampling.LANCZOS)

        # 计算图像粘贴位置
        paste_x = box_left + (box_width - new_width) // 2
        paste_y = box_upper

        # 生成合成图像
        img1_with_overlay = img1.copy()
        img1_with_overlay.paste(img2_resized, (paste_x, paste_y), img2_resized)

        # 根据 img1 的中心像素值选择混合模式
        if mode is None:
            center_x = img1_width // 2
            center_y = img1_height // 2
            center_pixel = img1.getpixel((center_x, center_y))

            # 计算该像素到黑色和白色的距离
            black_distance = np.linalg.norm(np.array(center_pixel[:3]) - np.array([0, 0, 0]))
            white_distance = np.linalg.norm(np.array(center_pixel[:3]) - np.array([255, 255, 255]))

            # 根据距离选择模式
            mode = 'lighten' if black_distance < white_distance else 'linear_burn'
        if is_mode_open:
            if mode == 'linear_burn':
                # 从 img1 中提取红框区域
                img1_part = img1.crop((box_left, box_upper, box_right, box_lower))
                img1_part_array = np.array(img1_part)
                # 计算 img2 的目标尺寸，保持比例缩放
                aspect_ratio = img2_resized.width / img2_resized.height
                if box_width / box_height > aspect_ratio:
                    # 如果框的宽高比大于图像的宽高比，按高度缩放
                    target_height = box_height
                    target_width = int(target_height * aspect_ratio)
                else:
                    # 按宽度缩放
                    target_width = box_width
                    target_height = int(target_width / aspect_ratio)
                # 缩放 img2 到目标尺寸
                img2_resized = img2_resized.resize((target_width, target_height), Image.Resampling.LANCZOS)
                img2_array_resized = np.array(img2_resized)
                # 计算位置偏移，使 img2 贴着盒子的上方
                offset_x = (box_width - target_width) // 2
                offset_y = 0  # 紧贴上方，所以偏移量为0
                # 创建一个全透明的图层，大小为盒子的尺寸
                img2_padded_array = np.zeros((box_height, box_width, 4), dtype=np.uint8)
                # 将 img2 放置到这个全透明的图层中
                img2_padded_array[offset_y:offset_y + target_height, offset_x:offset_x + target_width] = img2_array_resized
                # 处理透明度
                alpha_mask = img2_padded_array[:, :, 3] / 255.0 * 0.9  # 设置为90%不透明度
                img2_rgb = img2_padded_array[:, :, :3]
                img1_part_array = img1_part_array.astype(float)
                img2_rgb = img2_rgb.astype(float)
                # 线性加深模式，考虑透明度
                new_pixel = img1_part_array[:, :, :3] + img2_rgb - 255
                # 只在 img2 有效区域进行加深
                result_array_part = np.where(
                    alpha_mask[:, :, None] > 0,
                    np.clip(new_pixel, 0, 255) * alpha_mask[:, :, None] + img1_part_array[:, :, :3] * (
                            1 - alpha_mask[:, :, None]),
                    img1_part_array[:, :, :3]
                )
                # 合并透明度通道
                result_array_part = np.concatenate([result_array_part, img1_part_array[:, :, 3:]], axis=2)
                # 将处理结果转换为图像
                result_image_part = Image.fromarray(result_array_part.astype(np.uint8), 'RGBA')
                # 将处理后的区域粘贴回 img1
                img1.paste(result_image_part, (box_left, box_upper), result_image_part)
                # 保存合并后的图像
                img1.save(output_path)
            elif mode == 'lighten':
                # 计算图像粘贴位置
                paste_x = box_left + (box_width - new_width) // 2
                paste_y = box_upper
                # 生成合成图像
                img1_with_overlay = img1.copy()
                img1_with_overlay.paste(img2_resized, (paste_x, paste_y), img2_resized)
                # 转换为Numpy数组进行混合操作
                img1_array = np.array(img1)
                img2_array = np.array(img1_with_overlay)
                img1_array = img1_array.astype(float)
                img2_array = img2_array.astype(float)
                result_array = np.where(
                    img2_array[:, :, :3] > img1_array[:, :, :3],
                    img2_array[:, :, :3],
                    img1_array[:, :, :3]
                )
                result_array = np.concatenate([result_array, img1_array[:, :, 3:]], axis=2)
                # 将结果数组转换回图像
                result_image = Image.fromarray(result_array.astype(np.uint8), 'RGBA')
                # 保存合并后的图像
                result_image.save(output_path)
            else:
                raise ValueError("Unsupported mode. Use 'lighten' or 'linear_burn'.")
        else:
            img1_with_overlay = img1.copy()
            img1_with_overlay.paste(img2_resized, (paste_x, paste_y), img2_resized)
            img1_with_overlay.save(output_path)

    def list_image_files(self, folder_path):
        temp_list = []
        # 生成图片文件的路径列表
        image_extensions = ['*.png', '*.jpg', '*.jpeg', '*.bmp', '*.gif']  # 支持的图片扩展名
        file_paths = []
        for ext in image_extensions:
            file_paths.extend(glob.glob(os.path.join(folder_path, ext)))
        # 输出每个图片的路径
        for file_path in file_paths:
            temp_list.append(file_path)
        return temp_list

    # 如果需要得到最简比例，可以添加额外的逻辑来约简比例
    def get_simplest_ratio(self, image_path):
        """
        传入一个图片的文件路径，返回这个图片的最简比例（宽度/高度）。
        参数:
        image_path (str): 图片的文件路径。
        返回:
        fractions.Fraction: 图片的最简比例（宽度/高度）。
        """
        # 使用Pillow库打开图片
        with Image.open(image_path) as img:
            # 获取图片的宽度和高度
            width, height = img.size
            # 计算比例并找到最简分数
            ratio = fractions.Fraction(width, height).limit_denominator()
            return ratio

    def log(self, message):
        if self.log_signal:
            self.log_signal.emit(message)

    def get_filename_from_path(self, path):
        # 使用os.path.basename()获取路径中的文件名
        filename = os.path.basename(path)
        return filename

    async def main(self):
        ditu_path_list = self.list_image_files(self.ditu_file_path)
        show_path_list = self.list_image_files(self.sucai_file_path)
        # for ditu in ditu_path_list:
        #     simplified_ratio = str(self.get_simplest_ratio(ditu))  # 底图比例
        #     fixed_box = self.get_fixed_box(ditu, simplified_ratio)
        #     if fixed_box is None:
        #         self.log(f"未找到匹配的比例和类型: {ditu}，比例: {simplified_ratio}")
        #         continue
        # for show in show_path_list:
        #     uuid4 = uuid.uuid4()
        #     ditu_file_name = self.get_filename_from_path(ditu)
        #     sucai_file_name = self.get_filename_from_path(show)
        #     self.merge_images(f"{ditu}", f"{show}", f"{self.result_dir}/merged_output{uuid4}.png", fixed_box)
        #     self.log(f'当前底图_{ditu_file_name}_对应素材为_{sucai_file_name}')
        for show in show_path_list:
            for ditu in ditu_path_list:
                simplified_ratio = str(self.get_simplest_ratio(ditu))  # 底图比例
                fixed_box = self.get_fixed_box(ditu, simplified_ratio)
                if fixed_box is None:
                    self.log(f"未找到匹配的比例和类型: {ditu}，比例: {simplified_ratio}")
                    continue
                uuid4 = uuid.uuid4()
                ditu_file_name = self.get_filename_from_path(ditu)
                sucai_file_name = self.get_filename_from_path(show)

                self.merge_images(f"{ditu}", f"{show}", f"{self.result_dir}/{ditu_file_name}_{uuid4}.png", fixed_box, None, self.mode_open)
                self.log(f'当前底图_{ditu_file_name}_对应素材为_{sucai_file_name}')
        self.log(f'<span style="color:black;">图片生成完成:{self.result_dir}</span>')


class WorkerThread(QThread):
    log_signal = pyqtSignal(str)

    def __init__(self, file_path_1, file_path_2, result_dir, config_path, mode_open):
        super().__init__()
        self.worker = Worker(file_path_1, file_path_2, result_dir, config_path, self.log_signal, mode_open)

    def run(self):
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        loop.run_until_complete(self.worker.main())


class MainWindow(QMainWindow):
    def __init__(self):
        # 初始化config_data_dict为空字典
        self.config_data_dict = {}
        super().__init__()

        self.setWindowTitle('小助手_V1.1')
        self.setGeometry(100, 100, 800, 700)

        icon_bytes = QByteArray.fromBase64(icon_data.encode('utf-8'))
        icon_buffer = QBuffer()
        icon_buffer.setData(icon_bytes)
        icon_buffer.open(QIODevice.OpenModeFlag.ReadOnly)
        pixmap = QPixmap()
        pixmap.loadFromData(icon_buffer.data())
        icon = QIcon(pixmap)
        self.setWindowIcon(icon)

        main_layout = QHBoxLayout()

        # 左侧布局 - 文件选择、开始按钮和文本输出
        left_layout = QVBoxLayout()

        self.ditu_path_label = QLabel('请选择底图文件夹')
        left_layout.addWidget(self.ditu_path_label)

        self.ditu_path_input = QLineEdit()
        left_layout.addWidget(self.ditu_path_input)

        self.ditu_button = QPushButton('浏览')
        self.ditu_button.clicked.connect(self.browse_ditu_folder)
        left_layout.addWidget(self.ditu_button)

        self.sucai_path_label = QLabel('请选择素材文件夹')
        left_layout.addWidget(self.sucai_path_label)

        self.sucai_path_input = QLineEdit()
        left_layout.addWidget(self.sucai_path_input)

        self.sucai_button = QPushButton('浏览')
        self.sucai_button.clicked.connect(self.browse_sucai_folder)
        left_layout.addWidget(self.sucai_button)

        self.config_path_label = QLabel('请选择配置文件')
        left_layout.addWidget(self.config_path_label)

        self.config_path_input = QLineEdit()
        left_layout.addWidget(self.config_path_input)

        self.config_button = QPushButton('浏览')
        self.config_button.clicked.connect(self.browse_config_file)
        left_layout.addWidget(self.config_button)

        self.start_button = QPushButton('开始')
        self.start_button.clicked.connect(self.start_scraping)
        left_layout.addWidget(self.start_button)

        self.console_output = QTextEdit()
        self.console_output.setReadOnly(True)
        left_layout.addWidget(self.console_output)

        # 右侧布局 - 测试、展示和图片输出
        right_layout = QVBoxLayout()

        self.ditu_select_label = QLabel('选择底图')
        right_layout.addWidget(self.ditu_select_label)

        self.ditu_select_combobox = QComboBox()
        right_layout.addWidget(self.ditu_select_combobox)

        self.sucai_select_label = QLabel('选择素材')
        right_layout.addWidget(self.sucai_select_label)

        self.sucai_select_combobox = QComboBox()
        right_layout.addWidget(self.sucai_select_combobox)

        # 创建配置项下拉框及其相关输入框的水平布局
        config_layout = QHBoxLayout()
        # 创建一个是否开红框的复选框
        self.check_red = QCheckBox()
        self.check_red.setText('红框')
        self.check_red.setChecked(True)
        # 创建配置项下拉框
        test_config_select_update = QVBoxLayout()
        self.config_select_combobox = QComboBox()
        self.config_select_combobox.currentIndexChanged.connect(self.update_config_details)
        self.update_button = QPushButton('修改当前配置项')
        self.update_button.clicked.connect(self.update_config_files)
        test_config_select_update.addWidget(self.check_red)
        test_config_select_update.addWidget(self.config_select_combobox)
        test_config_select_update.addWidget(self.update_button)
        # 创建表单布局来容纳四个坐标输入框
        config_form_layout = QFormLayout()
        # 输入框
        self.config_detail_1_label = QLabel('X1')
        self.config_detail_1_input = QLineEdit()
        config_form_layout.addRow(self.config_detail_1_label, self.config_detail_1_input)
        self.config_detail_2_label = QLabel('Y1')
        self.config_detail_2_input = QLineEdit()
        config_form_layout.addRow(self.config_detail_2_label, self.config_detail_2_input)
        self.config_detail_3_label = QLabel('X2')
        self.config_detail_3_input = QLineEdit()
        config_form_layout.addRow(self.config_detail_3_label, self.config_detail_3_input)
        self.config_detail_4_label = QLabel('Y2')
        self.config_detail_4_input = QLineEdit()
        config_form_layout.addRow(self.config_detail_4_label, self.config_detail_4_input)
        config_layout.addLayout(test_config_select_update)
        config_layout.addLayout(config_form_layout)

        # 创建垂直布局放展示和保存
        test_save_layout = QVBoxLayout()
        # 创建一个是否开启混合操作的复选框
        self.check_hunhe = QCheckBox()
        self.check_hunhe.setText('混合处理')
        self.check_hunhe.setChecked(True)
        self.test_button = QPushButton('展示')
        self.test_button.clicked.connect(self.show_image_preview)
        self.save_button = QPushButton('保存')
        self.save_button.clicked.connect(self.show_image_preview)
        test_save_layout.addWidget(self.check_hunhe)
        test_save_layout.addWidget(self.test_button)
        test_save_layout.addWidget(self.save_button)
        config_layout.addLayout(test_save_layout)

        # 将水平布局添加到右侧布局中
        right_layout.addLayout(config_layout)

        self.image_preview_label = QLabel()
        self.image_preview_label.setFixedSize(500, 500)  # 固定图片展示区域的大小
        self.image_preview_label.setStyleSheet('background-color: lightgray;')  # 可选: 背景颜色
        right_layout.addWidget(self.image_preview_label)

        # 将左右布局添加到主布局中
        main_layout.addLayout(left_layout)
        main_layout.addLayout(right_layout)

        container = QWidget()
        container.setLayout(main_layout)
        self.setCentralWidget(container)

    def update_config_files(self):
        try:
            current_config = self.config_select_combobox.currentText()
            if current_config in self.config_data_dict:
                x1 = int(self.config_detail_1_input.text())
                y1 = int(self.config_detail_2_input.text())
                x2 = int(self.config_detail_3_input.text())
                y2 = int(self.config_detail_4_input.text())
                # 更新配置项中的box数据
                self.config_data_dict[current_config]['box'] = [x1, y1, x2, y2]
                # 更新config_data列表中的数据
                for i, item in enumerate(self.config_data):
                    if f"{item['type']}_{item['ratio']}" == current_config:
                        self.config_data[i] = self.config_data_dict[current_config]
                        break
                # 将更新后的数据写入config.json文件
                config_data_to_save = {'mappings': self.config_data}
                with open('../config.json', 'w', encoding='utf-8') as file:
                    json.dump(config_data_to_save, file, ensure_ascii=False, indent=4)
                self.log(F'当前配置文件:{self.config_data_dict[current_config]}已更新')
        except ValueError as e:
            self.log(f'<span style="color:red;">输入框中的数据格式错误: {e}</span>')
        except Exception as e:
            self.log(f'<span style="color:red;">更新配置文件时发生错误: {e}</span>')

    def save_img(self):
        pass

    def browse_ditu_folder(self):
        folder_path = QFileDialog.getExistingDirectory(self, "选择底图文件夹")
        if folder_path:
            self.ditu_path_input.setText(folder_path)
            self.load_ditu_images(folder_path)

    def browse_sucai_folder(self):
        folder_path = QFileDialog.getExistingDirectory(self, "选择素材文件夹")
        if folder_path:
            self.sucai_path_input.setText(folder_path)
            self.load_sucai_images(folder_path)

    def browse_config_file(self):
        config_path = QFileDialog.getOpenFileName(self, "选择配置文件", "", "Config Files (*.json);;All Files (*)")[0]
        if config_path:
            self.config_path_input.setText(config_path)
            self.load_configurations(config_path)

    def load_ditu_images(self, folder_path):
        self.ditu_select_combobox.clear()
        image_files = self.list_image_files(folder_path)
        self.ditu_select_combobox.addItems(image_files)

    def load_sucai_images(self, folder_path):
        self.sucai_select_combobox.clear()
        image_files = self.list_image_files(folder_path)
        self.sucai_select_combobox.addItems(image_files)

    def load_configurations(self, config_path):
        try:
            with open(config_path, 'r', encoding='utf-8') as file:
                self.config_data = json.load(file).get('mappings', [])
                config_dict = {
                    f"{item['type']}_{item['ratio']}": item
                    for item in self.config_data
                }
                self.config_select_combobox.clear()
                self.config_select_combobox.addItems(config_dict.keys())
                self.config_data_dict = config_dict

                # 加载配置文件后，选择第一个配置项并更新输入框
                if self.config_select_combobox.count() > 0:
                    self.config_select_combobox.setCurrentIndex(0)
                    self.update_config_details(0)
        except UnicodeDecodeError as e:
            self.log(f'<span style="color:red;">配置文件编码错误: {e}</span>')
            self.config_data = []
            self.config_data_dict = {}
        except json.JSONDecodeError as e:
            self.log(f'<span style="color:red;">配置文件格式错误: {e}</span>')
            self.config_data = []
            self.config_data_dict = {}
        except Exception as e:
            self.log(f'<span style="color:red;">加载配置文件时发生错误: {e}</span>')
            self.config_data = []

    def update_config_details(self, index):
        try:
            current_config = self.config_select_combobox.itemText(index)
            if current_config in self.config_data_dict:
                config_item = self.config_data_dict[current_config]
                box = config_item.get('box', [0, 0, 0, 0])
                self.config_detail_1_input.setText(str(box[0]))
                self.config_detail_2_input.setText(str(box[1]))
                self.config_detail_3_input.setText(str(box[2]))
                self.config_detail_4_input.setText(str(box[3]))
        except Exception as e:
            self.log(f'<span style="color:red;">更新配置详情时发生错误: {e}</span>')
            self.config_detail_1_input.setText('')
            self.config_detail_2_input.setText('')
            self.config_detail_3_input.setText('')
            self.config_detail_4_input.setText('')

    def list_image_files(self, folder_path):
        image_extensions = ['*.png', '*.jpg', '*.jpeg', '*.bmp', '*.gif']
        image_files = []
        for ext in image_extensions:
            image_files.extend(glob.glob(os.path.join(folder_path, ext)))
        return image_files

    def dir_is_True(self, dir_path):
        # 检查目录是否存在
        if not os.path.exists(dir_path):
            print(dir_path)
            # 如果目录不存在，则创建
            os.makedirs(dir_path)

    def show_image_preview(self):
        sender = self.sender()  # 获取发送信号的对象
        # if sender == self.test_button:
        #     # 如果是测试按钮触发
        #     self.log('测试按钮触发了 show_image_preview 方法')
        # elif sender == self.save_button:
        #     # 如果是保存按钮触发
        #     self.log('保存按钮触发了 show_image_preview 方法')
        try:
            ditu_path = self.ditu_select_combobox.currentText()
            sucai_path = self.sucai_select_combobox.currentText()
            selected_config = self.config_select_combobox.currentText()
            if not ditu_path or not sucai_path or not selected_config:
                self.log('请选择底图、素材和配置项。')
                return
            if selected_config not in self.config_data_dict:
                self.log('无效的配置项。')
                return
            # box = self.config_data_dict[selected_config].get('box', None)
            x1 = int(self.config_detail_1_input.text())
            y1 = int(self.config_detail_2_input.text())
            x2 = int(self.config_detail_3_input.text())
            y2 = int(self.config_detail_4_input.text())
            box = (x1, y1, x2, y2)
            if self.check_hunhe.isChecked() and self.check_red.isChecked():
                if sender == self.test_button:
                    self.merge_images(img1_path=ditu_path, img2_path=sucai_path, output_path=None, box=box, mode=None,
                                      is_open_mode=True, is_red_open=True)
                else:
                    self.dir_is_True(F'{script_dir}/TEST_IMG')
                    unique_id = str(uuid.uuid4()).replace('-', '')
                    output_path = F'{script_dir}/TEST_IMG/{unique_id}.png'
                    self.merge_images(img1_path=ditu_path, img2_path=sucai_path, output_path=output_path, box=box,
                                      mode=None,
                                      is_open_mode=True, is_red_open=True)
            elif not self.check_hunhe.isChecked() and self.check_red.isChecked():
                if sender == self.test_button:
                    self.merge_images(img1_path=ditu_path, img2_path=sucai_path, output_path=None, box=box, mode=None,
                                      is_open_mode=False, is_red_open=True)
                else:
                    self.dir_is_True(F'{script_dir}/TEST_IMG')
                    unique_id = str(uuid.uuid4()).replace('-', '')
                    output_path = F'{script_dir}/TEST_IMG/{unique_id}.png'
                    self.merge_images(img1_path=ditu_path, img2_path=sucai_path, output_path=output_path, box=box,
                                      mode=None,
                                      is_open_mode=False, is_red_open=True)
            elif self.check_hunhe.isChecked() and not self.check_red.isChecked():
                if sender == self.test_button:
                    self.merge_images(img1_path=ditu_path, img2_path=sucai_path, output_path=None, box=box, mode=None,
                                      is_open_mode=True, is_red_open=False)
                else:
                    self.dir_is_True(F'{script_dir}/TEST_IMG')
                    unique_id = str(uuid.uuid4()).replace('-', '')
                    output_path = F'{script_dir}/TEST_IMG/{unique_id}.png'
                    self.merge_images(img1_path=ditu_path, img2_path=sucai_path, output_path=output_path, box=box,
                                      mode=None,
                                      is_open_mode=True, is_red_open=False)
            elif not self.check_hunhe.isChecked() and not self.check_red.isChecked():
                if sender == self.test_button:
                    self.merge_images(img1_path=ditu_path, img2_path=sucai_path, output_path=None, box=box, mode=None,
                                      is_open_mode=False, is_red_open=False)
                else:
                    self.dir_is_True(F'{script_dir}/TEST_IMG')
                    unique_id = str(uuid.uuid4()).replace('-', '')
                    output_path = F'{script_dir}/TEST_IMG/{unique_id}.png'
                    self.merge_images(img1_path=ditu_path, img2_path=sucai_path, output_path=output_path, box=box,
                                      mode=None,
                                      is_open_mode=False, is_red_open=False)

        except Exception as e:
            self.log(f'展示图片时发生错误: {e}')

    def merge_images(self, img1_path, img2_path, output_path, box, mode=None, is_open_mode=True, is_red_open=True):
        """
        合并两张图片，并应用指定的混合模式
        :param is_red_open: 是否开启红框
        :param is_open_mode: 是否开启混合模式
        :param img1_path: 底图图片路径
        :param img2_path: 素材图片路径
        :param output_path: 输出文件路径
        :param box: 素材贴图盒子
        :param mode: 混合模式 ('lighten' 或 'linear_burn')，如果为 None 则根据 img1 的中心像素确定
        :return:
        """
        img1 = Image.open(img1_path).convert("RGBA")
        img2 = Image.open(img2_path).convert("RGBA")
        img1_width, img1_height = img1.size
        img2_width, img2_height = img2.size

        # 新定义的 box 值
        top_dist, bottom_dist, left_dist, right_dist = box

        # 计算红框的坐标
        box_left = left_dist
        box_upper = top_dist
        box_right = img1_width - right_dist
        box_lower = img1_height - bottom_dist

        # 计算红框的宽度和高度
        box_width = box_right - box_left
        box_height = box_lower - box_upper

        # 缩放 img2 以适应红框的宽度
        width_ratio = box_width / img2_width
        scale_ratio = width_ratio

        new_width = int(img2_width * scale_ratio)
        new_height = int(img2_height * scale_ratio)
        img2_resized = img2.resize((new_width, new_height), Image.Resampling.LANCZOS)

        # 如果缩放后的图像高度超出红框范围，根据高度缩放
        if img2_resized.height > box_height:
            height_ratio = box_height / img2_resized.height
            scale_ratio = height_ratio
            new_width = int(img2_resized.width * scale_ratio)
            new_height = int(img2_resized.height * scale_ratio)
            img2_resized = img2_resized.resize((new_width, new_height), Image.Resampling.LANCZOS)

        # 计算图像粘贴位置
        paste_x = box_left + (box_width - new_width) // 2
        paste_y = box_upper

        # if is_red_open:
        #     # 绘制红色框
        #     draw = ImageDraw.Draw(img1)
        #     draw.rectangle((box_left, box_upper, box_right, box_lower), outline="red", width=5)  # 设置框的颜色为红色，线条宽度为5

        # # 生成合成图像
        # img1_with_overlay = img1.copy()
        # img1_with_overlay.paste(img2_resized, (paste_x, paste_y), img2_resized)
        if not is_open_mode:  # 混合模式未开启
            if is_red_open:
                # 绘制红色框
                draw = ImageDraw.Draw(img1)
                draw.rectangle((box_left, box_upper, box_right, box_lower), outline="red", width=5)  # 设置框的颜色为红色，线条宽度为5
                # 生成合成图像
                img1_with_overlay = img1.copy()
                img1_with_overlay.paste(img2_resized, (paste_x, paste_y), img2_resized)
                if output_path is not None:
                    img1_with_overlay.save(output_path)
                    self.log(f'<span style="color:green;">当前测试图片保存到:{output_path}</span>')
            else:
                img1_with_overlay = img1.copy()
                img1_with_overlay.paste(img2_resized, (paste_x, paste_y), img2_resized)
                if output_path is not None:
                    img1_with_overlay.save(output_path)
                    self.log(f'<span style="color:green;">当前测试图片保存到:{output_path}</span>')

        # 根据 img1 的中心像素值选择混合模式
        if mode is None:
            center_x = img1_width // 2
            center_y = img1_height // 2
            center_pixel = img1.getpixel((center_x, center_y))
            # 计算该像素到黑色和白色的距离
            black_distance = np.linalg.norm(np.array(center_pixel[:3]) - np.array([0, 0, 0]))
            white_distance = np.linalg.norm(np.array(center_pixel[:3]) - np.array([255, 255, 255]))
            # 根据距离选择模式
            mode = 'lighten' if black_distance < white_distance else 'linear_burn'
        if is_open_mode:
            if mode == 'linear_burn':
                if is_red_open:
                    # 绘制红色框
                    draw = ImageDraw.Draw(img1)
                    draw.rectangle((box_left, box_upper, box_right, box_lower), outline="red", width=5)  # 设置框的颜色为红色，线条宽度为5
                # 从 img1 中提取红框区域
                img1_part = img1.crop((box_left, box_upper, box_right, box_lower))
                img1_part_array = np.array(img1_part)
                # 计算 img2 的目标尺寸，保持比例缩放
                aspect_ratio = img2_resized.width / img2_resized.height
                if box_width / box_height > aspect_ratio:
                    # 如果框的宽高比大于图像的宽高比，按高度缩放
                    target_height = box_height
                    target_width = int(target_height * aspect_ratio)
                else:
                    # 按宽度缩放
                    target_width = box_width
                    target_height = int(target_width / aspect_ratio)
                # 缩放 img2 到目标尺寸
                img2_resized = img2_resized.resize((target_width, target_height), Image.Resampling.LANCZOS)
                img2_array_resized = np.array(img2_resized)
                # 计算位置偏移，使 img2 贴着盒子的上方
                offset_x = (box_width - target_width) // 2
                offset_y = 0  # 紧贴上方，所以偏移量为0
                # 创建一个全透明的图层，大小为盒子的尺寸
                img2_padded_array = np.zeros((box_height, box_width, 4), dtype=np.uint8)
                # 将 img2 放置到这个全透明的图层中
                img2_padded_array[offset_y:offset_y + target_height,
                offset_x:offset_x + target_width] = img2_array_resized
                # 处理透明度
                alpha_mask = img2_padded_array[:, :, 3] / 255.0 * 0.9  # 设置为90%不透明度
                img2_rgb = img2_padded_array[:, :, :3]
                img1_part_array = img1_part_array.astype(float)
                img2_rgb = img2_rgb.astype(float)
                # 线性加深模式，考虑透明度
                new_pixel = img1_part_array[:, :, :3] + img2_rgb - 255
                # 只在 img2 有效区域进行加深
                result_array_part = np.where(
                    alpha_mask[:, :, None] > 0,
                    np.clip(new_pixel, 0, 255) * alpha_mask[:, :, None] + img1_part_array[:, :, :3] * (
                            1 - alpha_mask[:, :, None]),
                    img1_part_array[:, :, :3]
                )
                # 合并透明度通道
                result_array_part = np.concatenate([result_array_part, img1_part_array[:, :, 3:]], axis=2)
                # 将处理结果转换为图像
                result_image_part = Image.fromarray(result_array_part.astype(np.uint8), 'RGBA')
                # 将处理后的区域粘贴回 img1
                img1.paste(result_image_part, (box_left, box_upper), result_image_part)
                if output_path:
                    # 保存合并后的图像
                    img1.save(output_path)
                    self.log(f'<span style="color:green;">当前测试图片保存到:{output_path}</span>')
                img1 = img1.convert("RGB")
                qt_img = ImageQt(img1)
                pixmap = QPixmap.fromImage(qt_img)
                self.image_preview_label.setPixmap(pixmap.scaled(500, 500, Qt.AspectRatioMode.KeepAspectRatio))
                self.log(f'<span style="color:Orange;">当前素混合操作为线性加深</span>')
            elif mode == 'lighten':
                # 计算图像粘贴位置
                paste_x = box_left + (box_width - new_width) // 2
                paste_y = box_upper
                if is_red_open:
                    # 绘制红色框
                    draw = ImageDraw.Draw(img1)
                    draw.rectangle((box_left, box_upper, box_right, box_lower), outline="red", width=5)  # 设置框的颜色为红色，线条宽度为5
                # 生成合成图像
                img1_with_overlay = img1.copy()
                img1_with_overlay.paste(img2_resized, (paste_x, paste_y), img2_resized)
                # 转换为Numpy数组进行混合操作
                img1_array = np.array(img1)
                img2_array = np.array(img1_with_overlay)
                img1_array = img1_array.astype(float)
                img2_array = img2_array.astype(float)
                result_array = np.where(
                    img2_array[:, :, :3] > img1_array[:, :, :3],
                    img2_array[:, :, :3],
                    img1_array[:, :, :3]
                )
                result_array = np.concatenate([result_array, img1_array[:, :, 3:]], axis=2)
                # 将结果数组转换回图像
                result_image = Image.fromarray(result_array.astype(np.uint8), 'RGBA')
                if output_path:
                    # 保存合并后的图像
                    result_image.save(output_path)
                    self.log(f'<span style="color:green;">当前测试图片保存到:{output_path}</span>')
                qt_img = ImageQt(result_image)
                pixmap = QPixmap.fromImage(qt_img)
                self.image_preview_label.setPixmap(pixmap.scaled(500, 500, Qt.AspectRatioMode.KeepAspectRatio))
                self.log(f'<span style="color:Purple;">当前素混合操作为变亮</span>')
            else:
                raise ValueError("Unsupported mode. Use 'lighten' or 'linear_burn'.")
        else:
            # 生成合成图像
            img1_with_overlay = img1.copy()
            img1_with_overlay.paste(img2_resized, (paste_x, paste_y), img2_resized)
            qt_img = ImageQt(img1_with_overlay)
            pixmap = QPixmap.fromImage(qt_img)
            self.image_preview_label.setPixmap(pixmap.scaled(500, 500, Qt.AspectRatioMode.KeepAspectRatio))
            self.log(f'<span style="color:black;">当前没有混合操作</span>')

    def log(self, message):
        timestamp = QDateTime.currentDateTime().toString()
        html_info = f'<span style="color:blue;">[{timestamp}]</span> <span style="color:green;">{message}</span>'
        self.console_output.append(html_info)

    def start_scraping(self):
        global result_dir  # 当前脚本目录
        file_path_1 = self.ditu_path_input.text()
        file_path_2 = self.sucai_path_input.text()
        mode_open = self.check_hunhe.isChecked()
        if not file_path_1:
            self.log("请先选择一个文件夹。")
            return
        if not file_path_2:
            self.log("请先选择一个文件夹。")
            return
        unique_id = str(uuid.uuid4()).replace('-', '')
        folder_name = f"result_{unique_id}"
        try:
            os.mkdir(folder_name)
            print(f"文件夹 '{folder_name}' 创建成功")
        except FileExistsError:
            print(f"文件夹 '{folder_name}' 已存在")
        except OSError as error:
            print(f"创建文件夹时发生错误: {error}")
        result_dir = os.path.join(script_dir, f'{folder_name}')  # 输出文件夹 = 脚本目录 + 输出文件夹
        timestamp = QDateTime.currentDateTime().toString()
        self.console_output.append(f'<span style="color:blue;">[{timestamp}]</span> <span '
                                   f'style="color:black;">程序开始执行.....</span>')
        self.worker_thread = WorkerThread(file_path_1, file_path_2, result_dir, self.config_path_input.text(), mode_open)
        self.worker_thread.log_signal.connect(self.log)
        self.worker_thread.start()


if __name__ == '__main__':
    try:
        app = QApplication(sys.argv)
        main_window = MainWindow()
        main_window.show()
        main_window.log(f'<span style="color:black;">欢迎使用本软件.....</span>')
        sys.exit(app.exec())
    except Exception as e:
        with open('error_log.txt', 'a', encoding='utf-8') as log_file:
            log_file.write(f'Error during GUI initialization: {e}\n')
            log_file.write(traceback.format_exc())
